home *** CD-ROM | disk | FTP | other *** search
/ MacHack 1997 / MacHack 1997.toast / Hacks / Hacks ’96 / VideoFolder 1.0a / Source / ConvertToFinderIconPict.cp next >
Text File  |  1996-06-22  |  12KB  |  409 lines

  1. #include "ConvertToFinderIconPict.h"
  2. #include "Finder.h"
  3. #include "MoreFilesExtras.h"
  4. #include <QDOffscreen.h>
  5. #include <Palettes.h>
  6. #include <QDOffscreen.h>
  7. #include <stdio.h>
  8.  
  9.  
  10. const short kCustomIconResID = -16455;
  11.  
  12. CFinderIconPicture::CFinderIconPicture ( short vRefNum, long dirID ) :
  13.     mVRefNum ( vRefNum ),
  14.     mDirID ( dirID ),
  15.     mPix ( nil )
  16. {
  17. }
  18.  
  19. CFinderIconPicture::~CFinderIconPicture ( )
  20. {
  21.     TearDownPixMap();
  22. }
  23.  
  24. void CFinderIconPicture::AddCustomIconResource ( short refNum, OSType resType, GWorldPtr pic, Rect& r, unsigned short depth )
  25. {    Handle h = MakeIcon ( pic, & r, depth, 32 );
  26.  
  27.     if ( h )
  28.         AddResource ( h, resType, kCustomIconResID, "\p" );
  29. }
  30.  
  31. void CFinderIconPicture::CreateIconResourcesToFile ( GWorldPtr pic, short refNum, Rect& r )
  32. {    
  33.     Handle iconPound = MakeICN_pound ( pic, pic, & r, 32 );
  34.     AddResource ( iconPound, 'ICN#', kCustomIconResID, "\p" );
  35.     
  36.     AddCustomIconResource ( refNum, 'icl8', pic, r, 8 );
  37.     // AddCustomIconResource ( refNum, 'icl4', pic, r, 4 );
  38. }
  39.  
  40. static inline void PLstrcpy ( StringPtr dest, const StringPtr source )
  41. {
  42.     BlockMoveData ( source, dest, source[0] + 1 );
  43. }
  44.  
  45. static void UniqueXYFilename ( unsigned short x, unsigned short y, StringPtr str )
  46. {    const unsigned char spaceChar = ' ';
  47.     const unsigned char nonBreakingSpaceChar = 0x01;
  48.     
  49.     str[0] = 0;
  50.     
  51.     for ( short i = 14; i >= 0 ; i -- )
  52.         str[ ++ str[0] ] = ( y & ( 1 << i ) ) ? spaceChar : nonBreakingSpaceChar;
  53.  
  54.     for ( short i = 14; i >= 0 ; i -- )
  55.         str[ ++ str[0] ] = ( x & ( 1 << i ) ) ? spaceChar : nonBreakingSpaceChar;
  56.         
  57. }
  58.  
  59. void CFinderIconPicture::CreateTiledFile ( GWorldPtr pic, unsigned short x, unsigned short y )
  60. {    FSSpec spec;
  61.     Str255 fileName = "\pFile ";
  62.  
  63.     UniqueXYFilename ( x, y, fileName );
  64.     
  65.     if ( FSMakeFSSpec ( mVRefNum, mDirID, fileName, & spec ) == noErr )
  66.         FSpDelete ( & spec );
  67.         
  68.     FSpCreateResFile ( & spec, 'VFol', 'VFI#', smRoman );
  69.  
  70.     FInfo fileInfo;
  71.     if ( FSpGetFInfo ( & spec, & fileInfo ) == noErr )
  72.     {
  73.         fileInfo.fdLocation.h = x;
  74.         fileInfo.fdLocation.v = y;
  75.         fileInfo.fdFlags = kHasCustomIcon | kNameLocked | kHasBeenInited;
  76.         
  77.         FSpSetFInfo ( & spec, & fileInfo );
  78.     }
  79.     
  80.     short refNum = FSpOpenResFile ( & spec, fsRdWrPerm );
  81.     if ( refNum && ResError() == noErr )
  82.     {    Rect r;
  83.     
  84.         r.top = y;
  85.         r.bottom = y + 32;
  86.         
  87.         r.left = x;
  88.         r.right = x + 32;
  89.         
  90.         CreateIconResourcesToFile ( pic, refNum, r );
  91.  
  92.         CloseResFile ( refNum );
  93.  
  94.     }
  95. }
  96.  
  97. void CFinderIconPicture::DeleteExistingIcons ( )
  98. {
  99.     CInfoPBRec getCatInfoPB;
  100.     
  101.     getCatInfoPB.dirInfo.ioFDirIndex = 1;    /* get first item */
  102.  
  103.     OSErr err = noErr;
  104.     do
  105.     {    Str255 itemName = "\p";
  106.     
  107.         /* prepare to delete directory */
  108.         getCatInfoPB.dirInfo.ioNamePtr = itemName;
  109.         getCatInfoPB.dirInfo.ioVRefNum = mVRefNum;
  110.         getCatInfoPB.dirInfo.ioDrDirID = mDirID;    /* in this directory */
  111.         OSErr err = PBGetCatInfoSync(&(getCatInfoPB));
  112.         if ( err == noErr )
  113.         {
  114.             getCatInfoPB.dirInfo.ioFDirIndex ++;
  115.  
  116.             /* We have an item.  Is it a file or directory? */
  117.             if ( (getCatInfoPB.dirInfo.ioFlAttrib & ioDirMask) == 0 )
  118.             {
  119.                 if ( getCatInfoPB.hFileInfo.ioFlFndrInfo.fdType == 'VFI#' && getCatInfoPB.hFileInfo.ioFlFndrInfo.fdCreator == 'VFol' )
  120.                 {
  121.                     err = PBHDeleteSync( (HParamBlockRec*) &(getCatInfoPB));    /* delete this item */
  122.                     if ( err == noErr )
  123.                         getCatInfoPB.dirInfo.ioFDirIndex --;
  124.                 }
  125.                     
  126.                 if ( err == fLckdErr )
  127.                 {
  128.                     (void) PBHRstFLockSync( (HParamBlockRec*) &(getCatInfoPB));    /* unlock it */
  129.                     err = PBHDeleteSync( (HParamBlockRec*) &(getCatInfoPB));    /* and try again */
  130.                     if ( err == noErr )
  131.                         getCatInfoPB.dirInfo.ioFDirIndex --;
  132.                 }
  133.             }
  134.         }            
  135.     } while ( err == noErr );
  136. }
  137.  
  138. void CFinderIconPicture::AcceptPict ( GWorldPtr pic )
  139. {
  140.     //    "Tile" across the picture, creating icons for each file
  141.     // DeleteDirectoryContents ( mVRefNum, mDirID, "\p" );
  142.     
  143.     // DeleteExistingIcons ();
  144.     
  145.     Rect gWorldRect = pic->portRect;
  146.     for ( unsigned short y = gWorldRect.top; y < gWorldRect.bottom; y += 32 )
  147.     {
  148.         for ( unsigned short x = gWorldRect.left; x < gWorldRect.right; x += 32 )
  149.             CreateTiledFile ( pic, x, y );
  150.     }
  151. }
  152.  
  153. Handle    CFinderIconPicture::MakeICN_pound(GWorldPtr    gwp, GWorldPtr maskP, Rect *srcRect, short iconDimension)
  154. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  155.     this returns a handle to the image data for an icon and it's mask, of size iconDimension x iconDimension.
  156.     The icon is created by copying the srcRect of srcGWorld into a PixMap.
  157.   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  158. {    Handle    icon;
  159.     Handle    iconMask;
  160.     Size    iconSize;
  161.     
  162.     icon = MakeIcon(gwp, srcRect,1,iconDimension);            
  163.     
  164.     //    Once we've made the icon, create a mask of the icon which has 1 bits
  165.     //    for every place 'inside' the enclosing rectangle.
  166.     if(icon)
  167.     {    Handle iconMask = NewHandle ( GetHandleSize ( icon ) );
  168.         
  169.         for ( unsigned i = GetHandleSize ( iconMask ); i > 0; )
  170.             (*iconMask)[--i] = 0xff;
  171.         
  172.         if(iconMask)
  173.         {
  174.             iconSize = GetHandleSize(icon);
  175.             SetHandleSize(icon, iconSize + GetHandleSize(iconMask));
  176.             // CheckError("\pSetHandleSize fail.",MemError());
  177.             BlockMove(*iconMask, (Ptr)(((long)*icon) + iconSize), GetHandleSize(iconMask));            
  178.             DisposeHandle(iconMask);
  179.         }
  180.  
  181.     }
  182.         
  183.     return icon;
  184. }
  185.  
  186. Handle CFinderIconPicture::MakeIcon(GWorldPtr srcGWorld, Rect* srcRect, short dstDepth, short iconSize)
  187. /*
  188.     Creates a handle to the image data for an icon, or nil if an error.
  189.     The source image is specified by GWorld and regtangle defining the area
  190.     to create the icon from.
  191.     The type of icon is specified by the depth and Size paramters.
  192.     iconSize is used for both height and width.
  193.     For example, to create an Icl8 pass 8 for dstDepth and 32 for iconSize.
  194.     to create an ics8 pass 8 for the dstDepth and 16 for iconSize.
  195.     to create an ICON pass 1 for the dstDepth and 32 for iconSize.
  196.     
  197.     
  198. */
  199. {
  200.     GWorldPtr        saveWorld;
  201.     GDHandle        saveHandle;
  202.     long            bytesPerRow;
  203.     long            imageSize;
  204.     Handle            dstHandle;
  205.     Rect            iconFrame;
  206.     QDErr            err;
  207.     Rect            gWorldRect;
  208.     Rect            sourceRect = *srcRect;
  209.     
  210.     GetGWorld(&saveWorld,&saveHandle);        // save Graphics env state
  211.  
  212.     SetGWorld(srcGWorld,nil);
  213.     
  214.     iconFrame.top = 0;
  215.     iconFrame.left = 0;
  216.     iconFrame.bottom = iconSize;
  217.     iconFrame.right = iconSize;
  218.  
  219.     if ( mPix && ( ( (**mPix).pixelSize != dstDepth ) || ! EqualRect( & (**mPix).bounds, &iconFrame ) ) )
  220.         TearDownPixMap();
  221.  
  222.     // make a gworld for the icl resource
  223.     if ( ! mPix )
  224.     {
  225.         mPix = (PixMapHandle) NewHandleClear(sizeof(PixMap));
  226.     
  227.         /* See Tech Note #120 - for info on creating a PixMap by hand as SetUpPixMap
  228.             does.  SetUpPixMap was taken from that Tech Note....
  229.         */
  230.         // GWorldPtr destGWorld = nil;
  231.         // err = NewGWorld ( & destGWorld, dstDepth, & iconFrame, GetCTable(dstDepth+200), nil, useTempMem );
  232.         
  233.         CTabHandle colorTableH = GetCTable(dstDepth);
  234.         err =  SetUpPixMap(dstDepth,&iconFrame,colorTableH, mPix);
  235.         DisposeCTable ( colorTableH );
  236.  
  237.         if(err)
  238.             return nil;
  239.     }
  240.  
  241.     LockPixels( GetGWorldPixMap(srcGWorld) );
  242.     LockPixels(mPix);
  243.  
  244.     gWorldRect = srcGWorld->portRect;
  245.     if ( sourceRect.top < gWorldRect.top )
  246.     {    
  247.         iconFrame.top = gWorldRect.top - sourceRect.top;
  248.         sourceRect.top = gWorldRect.top;
  249.     }
  250.     
  251.     if ( sourceRect.left < gWorldRect.left )
  252.     {
  253.         iconFrame.left = gWorldRect.left - sourceRect.left;
  254.         sourceRect.left = gWorldRect.left;
  255.     }
  256.     
  257.     if ( sourceRect.bottom > gWorldRect.bottom )
  258.     {
  259.         iconFrame.bottom = iconFrame.bottom - ( sourceRect.bottom - gWorldRect.bottom );
  260.         sourceRect.bottom = gWorldRect.bottom;
  261.     }
  262.     
  263.     if ( sourceRect.right > gWorldRect.right )
  264.     {
  265.         iconFrame.right = iconFrame.right - ( sourceRect.right - gWorldRect.right );
  266.         sourceRect.right = gWorldRect.right;
  267.     }
  268.         
  269.     CopyBits( (BitMap*) *srcGWorld->portPixMap, (BitMap*) *mPix,
  270.                 & sourceRect, &iconFrame, srcCopy | ( dstDepth > 4 ) ?  ditherCopy : 0, nil);
  271.  
  272.     UnlockPixels(GetGWorldPixMap(srcGWorld));
  273.  
  274.      bytesPerRow = ((dstDepth * ((**mPix).bounds.right - (**mPix).bounds.left) + 31) / 32) * 4;
  275.     imageSize  = (bytesPerRow) * ((**mPix).bounds.bottom - (**mPix).bounds.top);
  276.  
  277.     SetZone ( ApplicationZone() );
  278.     dstHandle = NewHandleClear(imageSize);
  279.     err = MemError ();
  280.     if(err || dstHandle == nil)
  281.     {
  282.         return nil;    
  283.     }
  284.     HLock(dstHandle);
  285.     BlockMove(GetPixBaseAddr(mPix),*dstHandle,imageSize);
  286.     HUnlock(dstHandle);
  287.     UnlockPixels(mPix);
  288.     
  289.     // TearDownPixMap(mPix);
  290.     
  291.     // Restore graphics env to previous state
  292.     SetGWorld(saveWorld,saveHandle);
  293.     
  294.     HNoPurge(dstHandle);
  295.         
  296.     return dstHandle;
  297. }
  298.  
  299.  
  300. void CFinderIconPicture::TearDownPixMap()
  301. {
  302.     if ( mPix )
  303.     {
  304.         // We really need to do more....  BUT It is the thought that counts.. 
  305.         if ( (** mPix).pmTable )
  306.             DisposeCTable ( (**mPix).pmTable );
  307.         DisposePtr ( (**mPix).baseAddr );
  308.         
  309.         DisposeHandle( (Handle) mPix );
  310.     
  311.         mPix = nil;
  312.     }
  313. }
  314.  
  315. #define kDefaultRes 0x00480000 /* Default resolution is 72 DPI; Fixed type */
  316.  
  317. OSErr CFinderIconPicture::SetUpPixMap(
  318.     short        depth,       /* Desired number of bits/pixel in off-screen */
  319.     Rect         *bounds,     /* Bounding rectangle of off-screen */
  320.     CTabHandle   colors,      /* Color table to assign to off-screen */
  321.     PixMapHandle aPixMap      /* Handle to the PixMap being initialized */
  322.     )
  323. {
  324.     CTabHandle newColors;       /* Color table used for the off-screen PixMap */
  325.     Ptr        offBaseAddr;     /* Pointer to the off-screen pixel image */
  326.     OSErr      error;           /* Returns error code */
  327.     short      bytesPerRow;        /* Number of bytes per row in the PixMap */
  328.  
  329.  
  330.     error = noErr;
  331.     newColors = nil;
  332.     offBaseAddr = nil;
  333.  
  334.       bytesPerRow = ((depth * (bounds->right - bounds->left) + 31) / 32) * 4;
  335.  
  336.    /* Clone the clut if indexed color; allocate a dummy clut if direct color*/
  337.     if (depth <= 8)
  338.         {
  339.         newColors = colors;
  340.         error = HandToHand((Handle *) &newColors);
  341.         }
  342.     else
  343.         {
  344.         newColors = (CTabHandle) NewHandle(sizeof(ColorTable) -
  345.                 sizeof(CSpecArray));
  346.         error = MemError();
  347.         }
  348.     if (error == noErr)
  349.         {
  350.         /* Allocate pixel image; long integer multiplication avoids overflow */
  351.         offBaseAddr = NewPtrClear((unsigned long) bytesPerRow * (bounds->bottom -
  352.                 bounds->top));
  353.         if (offBaseAddr != nil)
  354.             {
  355.             /* Initialize fields common to indexed and direct PixMaps */
  356.             (**aPixMap).baseAddr = offBaseAddr;  /* Point to image */
  357.             (**aPixMap).rowBytes = bytesPerRow | /* MSB set for PixMap */
  358.                     0x8000;
  359.             (**aPixMap).bounds = *bounds;        /* Use given bounds */
  360.             (**aPixMap).pmVersion = 0;           /* No special stuff */
  361.             (**aPixMap).packType = 0;            /* Default PICT pack */
  362.             (**aPixMap).packSize = 0;            /* Always zero in mem */
  363.             (**aPixMap).hRes = kDefaultRes;      /* 72 DPI default res */
  364.             (**aPixMap).vRes = kDefaultRes;      /* 72 DPI default res */
  365.             (**aPixMap).pixelSize = depth;       /* Set # bits/pixel */
  366.             (**aPixMap).planeBytes = 0;          /* Not used */
  367.             (**aPixMap).pmReserved = 0;          /* Not used */
  368.  
  369.             /* Initialize fields specific to indexed and direct PixMaps */
  370.             if (depth <= 8)
  371.                 {
  372.                 /* PixMap is indexed */
  373.                 (**aPixMap).pixelType = 0;       /* Indicates indexed */
  374.                 (**aPixMap).cmpCount = 1;        /* Have 1 component */
  375.                 (**aPixMap).cmpSize = depth;     /* Component size=depth */
  376.                 (**aPixMap).pmTable = newColors; /* Handle to CLUT */
  377.                 }
  378.             else
  379.                 {
  380.                 /* PixMap is direct */
  381.                 (**aPixMap).pixelType = RGBDirect; /* Indicates direct */
  382.                 (**aPixMap).cmpCount = 3;          /* Have 3 components */
  383.                 if (depth == 16)
  384.                     (**aPixMap).cmpSize = 5;       /* 5 bits/component */
  385.                 else
  386.                     (**aPixMap).cmpSize = 8;       /* 8 bits/component */
  387.                 (**newColors).ctSeed = 3 * (**aPixMap).cmpSize;
  388.                 (**newColors).ctFlags = 0;
  389.                 (**newColors).ctSize = 0;
  390.                 (**aPixMap).pmTable = newColors;
  391.                 }
  392.             }
  393.         else
  394.             error = MemError();
  395.         }
  396.     else
  397.         newColors = nil;
  398.  
  399.     /* If no errors occured, return a handle to the new off-screen PixMap */
  400.     if (error != noErr)
  401.         {
  402.         if (newColors != nil)
  403.             DisposeCTable(newColors);
  404.         }
  405.  
  406.     /* Return the error code */
  407.     return error;
  408. }
  409.